package ssi.staaar;

import java.util.ArrayList;

import ssi.peeno.model.Message;
import ssi.staaar.util.GeoUtils;
import ssi.staaar.utility.camera.StaaarCameraView;
import ssi.staaar.view.StaaarMessageView;
import ssi.staaar.view.StaaarPrivateMessageView;
import ssi.staar.R;
import android.app.Activity;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.view.Display;
import android.view.Window;
import android.view.WindowManager;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.Animation;
import android.view.animation.ScaleAnimation;
import android.widget.FrameLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class ARActivity extends Activity implements SensorEventListener {
	private SensorManager sensorMan;
	private double azimuth;
	private float inclination;
	private static final int matrix_size=16;
	private ArrayList<Message> publicMessageList;
	private ArrayList<Message> privateMessageList;
	public double currentLat;
	public double currentLong;
	public double currentAlt;
	private int screenHeight;
	private int screenWidth;
	private float[] mags;
	private float[] accels;
	float[] R1 = new float[matrix_size];
	float[] outR = new float[matrix_size];
	float[] I = new float[matrix_size];
	float[] values = new float[3];
	private FrameLayout main;
	private StaaarCameraView cv;
	private ArrayList<StaaarMessageView> currentMessageView = new ArrayList<StaaarMessageView>();
	private float rawAzimuth;
	private float rawInclination;
	private float oldAzimuth;
	private float oldInclination;
	private TextView t1;
	public static volatile float kFilteringFactor = (float) 0.045; //o 0.05?
    private static int palloccoWidthMezzi = 33; //ovviamente si utilizza un metodo o altro per ricavare sti valori
    private static int palloccoHeightMezzi = 25;
	private static RelativeLayout relative;
    
	public void goToReadMessageActivity(StaaarMessageView cur) {
		Intent iReadMessage = new Intent();
	    iReadMessage.putExtra("Message.Current", cur.getMessage());
	    iReadMessage.setClass(getApplicationContext(), ReadMessageActivity.class);
	    startActivity(iReadMessage);
	}

	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
	}

	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		requestWindowFeature(Window.FEATURE_NO_TITLE);
		getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
		setContentView(R.layout.augmentedreality);
		sensorMan = (SensorManager) getSystemService(SENSOR_SERVICE);
		Intent callIntent = getIntent();
		currentLat = callIntent.getDoubleExtra("currentLat", 0.0);
		currentLong = callIntent.getDoubleExtra("currentLong", 0.0);
		currentAlt = callIntent.getDoubleExtra("currentAlt", 0.0);
		Log.d("[AUGMENTEDREALITY]", "latitudine: "+currentLat);
		Log.d("[AUGMENTEDREALITY]", "longitudine: "+currentLong);
		Log.d("[AUGMENTEDREALITY]", "altitudine: "+currentAlt);
		Display d = getWindowManager().getDefaultDisplay();
		screenHeight = d.getHeight();
		screenWidth = d.getWidth();
		main = (FrameLayout)findViewById(R.id.ARMainLayout);
		cv = new 
			StaaarCameraView(getApplicationContext());
		t1 = new TextView(getApplicationContext());
		main.addView(cv, screenWidth, screenHeight);
		main.addView(t1);
		relative = new RelativeLayout(this);
        relative.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        main.addView(relative);
		startSensor();
	}
	
	@Override
	public void onSensorChanged(SensorEvent event) {
		if (event.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
			return;
		switch (event.sensor.getType()) {
			case Sensor.TYPE_MAGNETIC_FIELD:
				mags = event.values.clone();
				break;
			case Sensor.TYPE_ACCELEROMETER:
				accels = event.values.clone();
				break;
		}
		if (mags != null && accels != null) {
			SensorManager.getRotationMatrix(R1, I, accels, mags);
			SensorManager.remapCoordinateSystem(R1, SensorManager.AXIS_X,
					SensorManager.AXIS_Z, outR);
			SensorManager.getOrientation(outR, values);
			rawAzimuth = (float) Math.round(Math.toDegrees(values[0]));
			azimuth = (rawAzimuth + 360)%360;
			azimuth = (float) ((rawAzimuth * kFilteringFactor) + (azimuth * (1.0 - kFilteringFactor)));
			inclination = (float) Math.round(Math.toDegrees(values[1]));
			inclination = (float)((rawInclination * kFilteringFactor) + (inclination * (1.0 - kFilteringFactor)));
			if (Math.abs(azimuth - oldAzimuth) > 3 || Math.abs(inclination - oldInclination) > 3) {
				//updateText();
				removeMessageView();
				updateARView();
				oldAzimuth = (float) azimuth;
				oldInclination = inclination;
			}
		}
	}

	@Override
	public void onPause(){
		stopSensor();
		super.onPause();
	}
	
	@Override
	public void onResume(){
		removeMessageView();
		main.invalidate();
		startSensor();
		super.onResume();
	}

	public void onStop() {
		stopSensor();
		super.onStop();
	}
	
	private void removeMessageView() {
		if (main != null && relative != null) {
			for (int i=0; i<currentMessageView.size(); ++i)
				main.removeView(currentMessageView.get(i));
			currentMessageView.clear();
			main.removeView(relative);
			relative.removeAllViews();
			main.addView(relative);
		}
	}

	public void scaleDown() {
		removeMessageView();
		updateARView();
		startSensor();
	}

	public void scaleUp(StaaarMessageView target) {
		stopSensor();
		removeMessageView();
		currentMessageView.add(target);
		float targetWidth = target.getX_length() * 2;
		float scaleFactor = (8*screenWidth/10)/targetWidth;
		target.setX(screenWidth/2);
		target.setY(screenHeight/2);
		main.addView(target);
		main.invalidate();
		ScaleAnimation animation = new ScaleAnimation(
				1.0f, scaleFactor,
				1.0f, scaleFactor,
				Animation.ABSOLUTE, (float)screenWidth/2, 
				Animation.ABSOLUTE, (float)screenHeight/2);
		animation.setInterpolator(getApplicationContext(), android.R.anim.accelerate_interpolator);
		animation.setDuration(500);
		animation.setFillAfter(true);
		target.startAnimation(animation);
		target.touch();
		target.setScale(scaleFactor);
	}

	public void startSensor() {
		sensorMan.registerListener(this, 
				sensorMan.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), 
				SensorManager.SENSOR_DELAY_UI);
		sensorMan.registerListener(this, 
				sensorMan.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), 
				SensorManager.SENSOR_DELAY_UI);
	}

	public void stopSensor() {
		sensorMan.unregisterListener(this);
	}
	
	private void updateARView() {		
		publicMessageList = MessageListActivity.getPublicMessageList();
		privateMessageList = MessageListActivity.getPrivateMessageList();
		int x,y;
		if (publicMessageList != null) {
			for (int i = 0; i < publicMessageList.size(); i++) {
				Message cur = publicMessageList.get(i);
				x = GeoUtils.getHorizontalPosition(cur.getLat(), cur.getLon(),
						currentLat, currentLong, azimuth, screenWidth);
				y = GeoUtils.getVerticalPosition(cur.getAlt(), cur.getDistance(), 
						currentAlt, inclination, screenHeight);
				if ((y > -palloccoHeightMezzi && y < screenHeight + palloccoHeightMezzi) && (x > -palloccoWidthMezzi && x < screenWidth + palloccoWidthMezzi)) {
					StaaarMessageView aMessage = new 
						StaaarMessageView(getApplicationContext(), cur, this);
					Log.d("[AR]", "[ARActivity] y: " + y);
					aMessage.setScreenWidth(screenWidth);
					aMessage.setScreenHeight(screenHeight);
					aMessage.setRelativeL(relative);
					aMessage.setX(x);
					aMessage.setY(y);
					aMessage.setContext(this);
					currentMessageView.add(aMessage);
					main.addView(aMessage);
				}
			}
		}
		if (privateMessageList != null) {
			for (int i = 0; i < privateMessageList.size(); i++) {
				Message cur = privateMessageList.get(i);
				x = GeoUtils.getHorizontalPosition(cur.getLat(), cur.getLon(), 
						currentLat, currentLong, azimuth, screenWidth);
				y = GeoUtils.getVerticalPosition(cur.getAlt(), cur.getDistance(), 
						currentAlt, inclination, screenHeight);
				if ((y > -palloccoHeightMezzi && y < screenHeight + palloccoHeightMezzi) && (x > -palloccoWidthMezzi && x < screenWidth + palloccoWidthMezzi)) {
					StaaarPrivateMessageView aMessage = new 
						StaaarPrivateMessageView(getApplicationContext(), cur, this);
					Log.d("[AR]", "[ARActivity] y: " + y);
					aMessage.setScreenWidth(screenWidth);
					aMessage.setScreenHeight(screenHeight);
					aMessage.setRelativeL(relative);
					aMessage.setX(x);
					aMessage.setY(y);
					aMessage.setContext(this);
					currentMessageView.add(aMessage);
					main.addView(aMessage);
				}
			}
		}
		main.invalidate();
	}

	private void updateText() {
		t1.setText("RAWAZIMUTH: " + rawAzimuth + "\n" +
		"RAWINCLINATION: " + rawInclination + "\n" +
		"AZIMUTH: " + azimuth + "\n " +
		"INCLINATION: " + inclination);
	}
}
